#include "lang.h"
#include "../sleipner_config.h"
#include "strman.h"
#include "ConvertUTF.h"


//#include <windows.h>
#include "util/mmgr.h"
#include "util/log.h"
#include "util/common_macros.h"		

#include <stdlib.h>
#include <wchar.h>

#include <stdarg.h>
#include <algorithm>
#include <cassert>


using namespace lang;

Lang::NEGATIVE_FORMAT	Lang::NegativeFormat = NF_NEGATIVE_IN_FRONT;
const std::string		Lang::INVALID_LOC_STRING = "INVALID_LOC_STRING";

std::wstring		Lang::ConvertAtoW(const std::string& str)
{
	if (str.empty()) return L"";


#ifdef _PLATFORM_ANDROID
	return UTFConverter::Instance().FromUtf8ToUtf16(str);
	//UnicodeA = RetV;
	//_LOG(MSG_COMMENT, "I am here ");
	//return (wchar_t*)UnicodeA;
#endif

	const unsigned short	UNICODE_C = 1024;
	unsigned short	UnicodeA[UNICODE_C ];
	size_t	StrLen = str.size();
	assert(StrLen < UNICODE_C); 
	memset(UnicodeA, 0, sizeof(UnicodeA));



#ifdef _PLATFORM_WIN32
	MultiByteToWideChar(CP_UTF8, 0,
						str.c_str(), (int)StrLen,
						UnicodeA, UNICODE_C);
#else

	//_LOG(MSG_COMMENT, "size of wchar_t" << sizeof(wchar_t));
	//_LOG(MSG_COMMENT, "ConvertAtoW 's parameter " << str );
	std::mbstowcs((wchar_t *)UnicodeA, str.c_str(),UNICODE_C);

#endif //_PLATFORM_WIN32

	return (wchar_t*)UnicodeA;

}

std::string	Lang::ConvertWtoA(const std::wstring& wstr)
{

#ifdef _PLATFORM_ANDROID
	return UTFConverter::Instance().FromUtf16ToUtf8(wstr);
#endif

	const unsigned short	STR_C = 1024;
	char	CharA[STR_C];
	if (wstr.empty()) return "";



	std::wstring Temp = wstr;
	int testsize = (int)Temp.size();
	if ((int)Temp.size() > STR_C) Temp.resize(STR_C-10);
	memset(CharA, 0, sizeof(CharA));

	std::string Res;
#ifdef _PLATFORM_WIN32
	WideCharToMultiByte(CP_UTF8, NULL,
						Temp.c_str(), (int)Temp.size(),
						CharA, STR_C,
						NULL, NULL);
	return CharA;
#endif


#ifdef _PLATFORM_WII
	return UTFConverter::Instance().FromUtf16ToUtf8(wstr);
#endif


#if defined(__APPLE__) || defined(_PLATFORM_ANDROID)

	mbstate_t state;
	memset (&state, '\0', sizeof (state));
	if (! mbsinit (&state))
	{
		int foo = 0;
	}
    const wchar_t   *wcsIndirectString = Temp.c_str();
	
	int Result = wcsrtombs(&CharA[0], &wcsIndirectString,  Temp.size(), &state);
	//_LOG(MSG_COMMENT, "ConvertWtoA " << CharA );
	return CharA;

#endif //__APPLE_
	return "";
}

std::string		Lang::FormatCommaNumber(int i, char separator, int grouping)
{
	const int MAX_DIGIT = 50;
	char DigitA[MAX_DIGIT];
	int	DigitC = 0;
	bool IsNegative = (i < 0);
	int num = abs(i);
	int	CommaCount = 0;

	if (IsNegative)
	{
		switch (NegativeFormat)
		{
		case NF_NEGATIVE_AT_BACK:
			DigitA[DigitC++] = '-';
			break;
		case NF_NEGATIVE_IN_BRACKETS:
			DigitA[DigitC++] = ')';
			break;
		}
	}
	
	while (num > 9)
	{
		DigitA[DigitC++] = '0' + (num % 10);
		num = num / 10;
		CommaCount++;
		if (separator && grouping && (CommaCount >= grouping))
		{
			CommaCount = 0;
			DigitA[DigitC++] = separator;
		}
	}
	DigitA[DigitC++] = '0' + num;

	if (IsNegative)
	{
		switch (NegativeFormat)
		{
		case NF_NEGATIVE_IN_FRONT:
			DigitA[DigitC++] = '-';
			break;
		case NF_NEGATIVE_IN_BRACKETS:
			DigitA[DigitC++] = '(';
			break;
		}
	}

	// reverse string
	std::string		Test;
	while (DigitC > 0)
	{
		Test += DigitA[--DigitC];
	}

	return Test;
}

std::string		Lang::FormatNumber(int i, bool comma)
{
	if (comma)
		return FormatCommaNumber(i);
	else
	{
		char szNum[256];
		sprintf(szNum, "%d", i);
		return szNum;
	}
}

std::string		Lang::FormatTimeNumber(float f)
{
	const int MAX_DIGIT = 50;
	char DigitA[MAX_DIGIT];
	int	DigitC = 0;

	int			Main = (int)f;
	int			Seconds = Main % 60;
	int			Minutes = Main / 60;


	float		Part = f - (float)Main;
	if (Seconds < 10)
		sprintf(DigitA, "%2i:0%i", Minutes, Seconds);
	else
		sprintf(DigitA, "%2i:%2i", Minutes, Seconds);
	return std::string(DigitA);
}


std::wstring	Lang::CombineLocStringA(const std::string& strA, const std::string& strB, bool AddSpace)
{
	// use for one-time combination rather than permanent UIManager::ReplaceWord

	std::wstring wstrA = lang::StrMan::Instance().GetStringA(strA);
	std::wstring wstrB = lang::StrMan::Instance().GetStringA(strB);

	if (wstrA.empty()) wstrA = Lang::ConvertAtoW(strA);
	if (wstrB.empty()) wstrB = Lang::ConvertAtoW(strB);

	if (AddSpace) wstrA += Lang::ConvertAtoW(" ");

	return (wstrA + wstrB);
}


std::string		Lang::ConvertStringToLoc(const std::string& str, bool EnforceLOCFormat)
{
	// convert a regular string to LOC format
	static const int BufSize = 64;

	char Buffer[BufSize];
	int idx = 0;
	int len = UTIL_LOW(BufSize-1, (int)str.size());
	int HasSpace = 0;

	for (int i = 0; i < len; i++)
	{
		unsigned char ch = str.c_str()[i];

		// operate only on valid ASCII characters -- no foreign alphabets
		if (ch == 0x5f) // underscore
		{
			Buffer[idx++] = (char)ch;
			HasSpace++;
		}
		else if ((ch < 0xFF) && (isspace(ch) || ispunct(ch))) // spaces and punctuation
		{
			if ((idx == 0) || (i == (len-1)) || (0x5f == Buffer[idx-1]))
				continue; // ignore leading or trailing space

			Buffer[idx++] = (char)ch;
			HasSpace++;
		}
		else if ((ch >= 0x41) && (ch <= 0x5A)) // upper case
		{
			Buffer[idx++] = (char)ch;
		}
		else if ((ch >= 0x61) && (ch <= 0x7A)) // lower case
		{
			Buffer[idx++] = (char)(ch - 32);
		}
		else if ((ch >= 0x30) && (ch <= 0x39)) // numerals
		{
			Buffer[idx++] = (char)ch;
		}
		// else ignore all other symbols
	}

	if (idx == 0)
		return INVALID_LOC_STRING;

	// (corner case) eliminate trailing space
	if (0x5f == Buffer[idx-1])
	{
		idx--;
		HasSpace--;
	}

	// close the buffer
	Buffer[idx++] = 0;

	if (EnforceLOCFormat && (HasSpace == 0))
	{
		// generally loc string format should be XXX_YYY, so let's pad something to it
		return std::string(Buffer) += "_TXT";
	}

	return Buffer;
}


std::wstring Lang::CreateParamStringA(const std::string& LocStr, int ParamC, ...)
{
	// use for one-time parameter replacement rather than permanent UIManager::ReplaceWord

	static const std::wstring Marker = ConvertAtoW("%PARAM%");
	static const std::wstring::size_type MarkerLen = Marker.size();

	std::wstring wstrOut = StrMan::Instance().GetStringA(LocStr);

	

	return wstrOut;
}

std::wstring Lang::CreateParamStringW(const std::string& LocStr, int ParamC, ...)
{
	// use for one-time parameter replacement rather than permanent UIManager::ReplaceWord

	static const std::wstring Marker = ConvertAtoW("%PARAM%");
	static const std::wstring::size_type MarkerLen = Marker.size();

	std::wstring wstrOut = StrMan::Instance().GetStringA(LocStr);



	return wstrOut;
}


std::string Lang::FormatTimeMMSS(int Time)
{
	int Min, Sec;
	char szVal[256];

	Min = (Time / 60);
	Sec = Time % 60;

	sprintf(szVal, "%d:%.2d", Min, Sec);
	return szVal;
}

std::string Lang::FormatTimeHHMMSS(int Time)
{
	int Hours, Min, Sec;
	char szVal[256];

	Hours = (Time / 3600);
	Min = (Time / 60) % 60;
	Sec = Time % 60;

	sprintf(szVal, "%d:%.2d:%.2d", Hours, Min, Sec);
	return szVal;
}

std::string Lang::FormatDashNumber(int Num)
{
	int Idx = 0;
	int Digits;
	char szNum[256];
	char szResult[256];

	sprintf(szNum, "%d", abs(Num));
	Digits = (int)strlen(szNum);

	if (Num < 0)
		szResult[Idx++] = '-';

	for (int i = 0; i < Digits; i++)
	{
		if ((i > 0) && (i < (Digits - 1)) && (((Digits - i) % 3) == 0))
			szResult[Idx++] = ',';
		szResult[Idx++] = szNum[i];
	}
	szResult[Idx] = 0;

	return szResult;
}

std::vector<std::string> Lang::Tokenize(const std::string& str,const std::string& delimiters,bool Trim)
{
	using namespace std;
	vector<string> tokens;

	std::string	SkipSet = delimiters;
	// skip delimiters at beginning.
    	string::size_type lastPos = str.find_first_not_of(SkipSet, 0);
    	
	// find first "non-delimiter".
    	string::size_type pos = str.find_first_of(delimiters, lastPos);

    	while (string::npos != pos || string::npos != lastPos)
    	{
        	// found a token, add it to the vector.
			std::string	Token = str.substr(lastPos, pos - lastPos);
			if(Trim)
			{
				Token = TrimLeading(Token);
				Token = TrimTrailing(Token);
			}
			if (!Token.empty())
			{
        		tokens.push_back(Token);
			}
		
        	// skip delimiters.  Note the "not_of"
        	lastPos = str.find_first_not_of(SkipSet, pos);
		
        	// find next "non-delimiter"
        	pos = str.find_first_of(delimiters, lastPos);
    	}

	return tokens;
}



// trim trailing spaces
std::string	Lang::TrimTrailing(const std::string str)
{
	char	A = str[0];
	char	B = str[1];
	size_t endpos = str.find_last_not_of(" \t");
	if( std::string::npos != endpos )
	{
		return str.substr( 0, endpos+1 );
	} else
	{
		return "";
	}
}

std::string	Lang::TrimLeading(const std::string str)
{
	char	A = str[0];
	char	B = str[1];
	size_t startpos = str.find_first_not_of(" \t");
	if( std::string::npos != startpos )
	{
		return str.substr( startpos );
	} else
	{
		return "";
	}
}

std::string			Lang::Format(const char*  _Msg, ...)
{
	char Message[1024];
	va_list ArgP;
	va_start(ArgP, _Msg);
	vsprintf(Message, _Msg, ArgP);
	va_end(ArgP);

	return std::string(Message);
}
